package com.wstuo.common.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;

/**
 * 
 * @version 1.00 
 * @author wstuo.com
 */
@SuppressWarnings("unchecked")
public abstract class ObjectUtils {

	private static final int INITIAL_HASH = 7;
	private static final int MULTIPLIER = 31;
	private static final String EMPTY_STRING = "";
	private static final String NULL_STRING = "null";
	private static final String ARRAY_START = "{";
	private static final String ARRAY_END = "}";
	private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END;
	private static final String ARRAY_ELEMENT_SEPARATOR = ", ";
	private static final Logger LOGGER = Logger.getLogger(ObjectUtils.class);

	public static boolean isCheckedException(Throwable ex) {

		return !(ex instanceof RuntimeException || ex instanceof Error);
	}

	public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) {
		boolean result = false;
		if (isCheckedException(ex)) {
			if (declaredExceptions != null) {

				for (int i = 0; i < declaredExceptions.length; i++) {

					if (declaredExceptions[i].isAssignableFrom(ex.getClass())) {
						result = true;
						break;
					}
				}
			}
		} else {
			result = true;
		}

		return result;
	}

	public static boolean isEmpty(Object[] array) {

		return ((array == null) || (array.length == 0));
	}

	public static Object[] addObjectToArray(Object[] array, Object obj) {

		Class compType = Object.class;

		if (array != null) {

			compType = array.getClass().getComponentType();
		} else if (obj != null) {

			compType = obj.getClass();
		}

		int newArrLength = ((array != null) ? (array.length + 1) : 1);
		Object[] newArr = (Object[]) Array.newInstance(compType, newArrLength);

		if (array != null) {

			System.arraycopy(array, 0, newArr, 0, array.length);
		}

		newArr[newArr.length - 1] = obj;

		return newArr;
	}
	public static Object[] toObjectArray(Object source) {

		if (source instanceof Object[]) {

			return (Object[]) source;
		}

		if (source == null) {

			return new Object[0];
		}

		if (!source.getClass().isArray()) {

			throw new IllegalArgumentException("Source is not an array: " + source);
		}

		int length = Array.getLength(source);

		if (length == 0) {

			return new Object[0];
		}

		Class wrapperType = Array.get(source, 0).getClass();
		Object[] newArray = (Object[]) Array.newInstance(wrapperType, length);

		for (int i = 0; i < length; i++) {

			newArray[i] = Array.get(source, i);
		}

		return newArray;
	}
	public static boolean nullSafeEquals(Object o1, Object o2) {

		if (o1 == o2) {

			return true;
		}

		if ((o1 == null) || (o2 == null)) {

			return false;
		}

		if (o1.equals(o2)) {

			return true;
		}

		if (o1 instanceof Object[] && o2 instanceof Object[]) {

			return Arrays.equals((Object[]) o1, (Object[]) o2);
		}

		if (o1 instanceof boolean[] && o2 instanceof boolean[]) {

			return Arrays.equals((boolean[]) o1, (boolean[]) o2);
		}

		if (o1 instanceof byte[] && o2 instanceof byte[]) {

			return Arrays.equals((byte[]) o1, (byte[]) o2);
		}

		if (o1 instanceof char[] && o2 instanceof char[]) {

			return Arrays.equals((char[]) o1, (char[]) o2);
		}

		if (o1 instanceof double[] && o2 instanceof double[]) {

			return Arrays.equals((double[]) o1, (double[]) o2);
		}

		if (o1 instanceof float[] && o2 instanceof float[]) {

			return Arrays.equals((float[]) o1, (float[]) o2);
		}

		if (o1 instanceof int[] && o2 instanceof int[]) {

			return Arrays.equals((int[]) o1, (int[]) o2);
		}

		if (o1 instanceof long[] && o2 instanceof long[]) {

			return Arrays.equals((long[]) o1, (long[]) o2);
		}

		if (o1 instanceof short[] && o2 instanceof short[]) {

			return Arrays.equals((short[]) o1, (short[]) o2);
		}

		return false;
	}
	public static int nullSafeHashCode(Object obj) {

		if (obj == null) {

			return 0;
		}

		if (obj instanceof Object[]) {

			return nullSafeHashCode((Object[]) obj);
		}

		if (obj instanceof boolean[]) {

			return nullSafeHashCode((boolean[]) obj);
		}

		if (obj instanceof byte[]) {

			return nullSafeHashCode((byte[]) obj);
		}

		if (obj instanceof char[]) {

			return nullSafeHashCode((char[]) obj);
		}

		if (obj instanceof double[]) {

			return nullSafeHashCode((double[]) obj);
		}

		if (obj instanceof float[]) {

			return nullSafeHashCode((float[]) obj);
		}

		if (obj instanceof int[]) {

			return nullSafeHashCode((int[]) obj);
		}

		if (obj instanceof long[]) {

			return nullSafeHashCode((long[]) obj);
		}

		if (obj instanceof short[]) {

			return nullSafeHashCode((short[]) obj);
		}

		return obj.hashCode();
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(Object[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + nullSafeHashCode(array[i]);
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(boolean[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + hashCode(array[i]);
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(byte[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + array[i];
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(char[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + array[i];
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(double[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + hashCode(array[i]);
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(float[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + hashCode(array[i]);
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(int[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + array[i];
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(long[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + hashCode(array[i]);
		}

		return hash;
	}

	/**
	 * Return a hash code based on the contents of the specified array. If <code>array</code> is <code>null</code>, this method returns 0.
	 */
	public static int nullSafeHashCode(short[] array) {

		if (array == null) {

			return 0;
		}

		int hash = INITIAL_HASH;
		int arraySize = array.length;

		for (int i = 0; i < arraySize; i++) {

			hash = (MULTIPLIER * hash) + array[i];
		}

		return hash;
	}

	/**
	 * Return the same value as <code>{@link Boolean#hashCode()}</code>.
	 * 
	 * @see Boolean#hashCode()
	 */
	public static int hashCode(boolean bool) {

		return bool ? 1231 : 1237;
	}

	/**
	 * Return the same value as <code>{@link Double#hashCode()}</code>.
	 * 
	 * @see Double#hashCode()
	 */
	public static int hashCode(double dbl) {

		long bits = Double.doubleToLongBits(dbl);

		return hashCode(bits);
	}

	/**
	 * Return the same value as <code>{@link Float#hashCode()}</code>.
	 * 
	 * @see Float#hashCode()
	 */
	public static int hashCode(float flt) {

		return Float.floatToIntBits(flt);
	}

	/**
	 * Return the same value as <code>{@link Long#hashCode()}</code>.
	 * 
	 * @see Long#hashCode()
	 */
	public static int hashCode(long lng) {

		return (int) (lng ^ (lng >>> 32));
	}

	// ---------------------------------------------------------------------
	// Convenience methods for toString output
	// ---------------------------------------------------------------------

	/**
	 * Return a String representation of an object's overall identity.
	 * 
	 * @param obj
	 *            the object (may be <code>null</code>)
	 * @return the object's identity as String representation, or <code>null</code> if the object was <code>null</code>
	 */
	public static String identityToString(Object obj) {

		if (obj == null) {

			return EMPTY_STRING;
		}

		return obj.getClass().getName() + "@" + getIdentityHexString(obj);
	}

	/**
	 * Return a hex String form of an object's identity hash code.
	 * 
	 * @param obj
	 *            the object
	 * @return the object's identity code in hex notation
	 */
	public static String getIdentityHexString(Object obj) {

		return Integer.toHexString(System.identityHashCode(obj));
	}

	/**
	 * Return a content-based String representation if <code>obj</code> is not <code>null</code>; otherwise returns an empty String.
	 * <p>
	 * Differs from {@link #nullSafeToString(Object)} in that it returns an empty String rather than "null" for a <code>null</code> value.
	 * 
	 * @param obj
	 *            the object to build a display String for
	 * @return a display String representation of <code>obj</code>
	 * @see #nullSafeToString(Object)
	 */
	public static String getDisplayString(Object obj) {

		if (obj == null) {

			return EMPTY_STRING;
		}

		return nullSafeToString(obj);
	}

	/**
	 * Determine the class name for the given object.
	 * <p>
	 * Returns <code>"null"</code> if <code>obj</code> is <code>null</code>.
	 * 
	 * @param obj
	 *            the object to introspect (may be <code>null</code>)
	 * @return the corresponding class name
	 */
	public static String nullSafeClassName(Object obj) {

		return ((obj != null) ? obj.getClass().getName() : NULL_STRING);
	}

	/**
	 * Return a String representation of the specified Object.
	 * <p>
	 * Builds a String representation of the contents in case of an array. Returns <code>"null"</code> if <code>obj</code> is <code>null</code>.
	 * 
	 * @param obj
	 *            the object to build a String representation for
	 * @return a String representation of <code>obj</code>
	 */
	public static String nullSafeToString(Object obj) {

		if (obj == null) {

			return NULL_STRING;
		}

		if (obj instanceof String) {

			return (String) obj;
		}

		if (obj instanceof Object[]) {

			return nullSafeToString((Object[]) obj);
		}

		if (obj instanceof boolean[]) {

			return nullSafeToString((boolean[]) obj);
		}

		if (obj instanceof byte[]) {

			return nullSafeToString((byte[]) obj);
		}

		if (obj instanceof char[]) {

			return nullSafeToString((char[]) obj);
		}

		if (obj instanceof double[]) {

			return nullSafeToString((double[]) obj);
		}

		if (obj instanceof float[]) {

			return nullSafeToString((float[]) obj);
		}

		if (obj instanceof int[]) {

			return nullSafeToString((int[]) obj);
		}

		if (obj instanceof long[]) {

			return nullSafeToString((long[]) obj);
		}

		if (obj instanceof short[]) {

			return nullSafeToString((short[]) obj);
		}

		return obj.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(Object[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(String.valueOf(array[i]));
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(boolean[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(byte[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(char[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append("'").append(array[i]).append("'");
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(double[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(float[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(int[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(long[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Return a String representation of the contents of the specified array.
	 * <p>
	 * The String representation consists of a list of the array's elements, enclosed in curly braces (<code>"{}"</code>). Adjacent elements are separated by the characters <code>", "</code> (a comma followed by a space). Returns <code>"null"</code> if <code>array</code> is <code>null</code>.
	 * 
	 * @param array
	 *            the array to build a String representation for
	 * @return a String representation of <code>array</code>
	 */
	public static String nullSafeToString(short[] array) {

		if (array == null) {

			return NULL_STRING;
		}

		int length = array.length;

		if (length == 0) {

			return EMPTY_ARRAY;
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < length; i++) {

			if (i == 0) {

				buffer.append(ARRAY_START);
			} else {

				buffer.append(ARRAY_ELEMENT_SEPARATOR);
			}

			buffer.append(array[i]);
		}

		buffer.append(ARRAY_END);

		return buffer.toString();
	}

	/**
	 * Copy not null properties to the destination object from the originate object.
	 * 
	 * @param dest
	 *            the destination object
	 * @param orig
	 *            the originate object
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyNotNullProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {
		if (dest == null)
			throw new IllegalArgumentException("No destination bean specified");
		if (orig == null)
			throw new IllegalArgumentException("No origin bean specified");
		if (orig instanceof DynaBean) {
			DynaProperty origDescriptors[] = ((DynaBean) orig).getDynaClass().getDynaProperties();
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();

				if (PropertyUtils.isReadable(orig, name) && PropertyUtils.isWriteable(dest, name)) {
					Object value = ((DynaBean) orig).get(name);
					BeanUtils.copyProperty(dest, name, value);
				}
			}

		} else if (orig instanceof Map) {
			for (Iterator entries = ((Map) orig).entrySet().iterator(); entries.hasNext();) {
				java.util.Map.Entry entry = (java.util.Map.Entry) entries.next();
				String name = (String) entry.getKey();
				if (PropertyUtils.isWriteable(dest, name))
					BeanUtils.copyProperty(dest, name, entry.getValue());
			}

		} else {
			PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);
			for (int i = 0; i < origDescriptors.length; i++) {
				String name = origDescriptors[i].getName();
				if (!"class".equals(name) && PropertyUtils.isReadable(orig, name) && PropertyUtils.isWriteable(dest, name))
					try {
						Object value = PropertyUtils.getSimpleProperty(orig, name);
						if (value != null)
							BeanUtils.copyProperty(dest, name, value);
					} catch (NoSuchMethodException nosuchmethodexception) {
						LOGGER.error(nosuchmethodexception);
					}
			}
		}
	}


	/**
	 * 对比两个同类型的List<Object> 返回差异List<Object>集合
	 * @param newModel 修改后的数据集合
	 * @param oldModel 原始数据集合
	 * @return List<Object> 返回与原始集合有差异的集合
	 */
	public static List<? extends Object> getDifferenceSetsList(List<? extends Object> newModel, List<? extends Object> oldModel) {
		Map<Object, Integer> map = new HashMap<Object, Integer>(newModel.size() + oldModel.size());
		List<Object> list = new ArrayList<Object>();
		List<Object> maxList = (List<Object>) newModel;
		List<Object> minList = (List<Object>) oldModel;
		if (oldModel.size() > newModel.size()) {
			maxList = (List<Object>) oldModel;
			minList = (List<Object>) newModel;
		}
		for (Object obj : maxList) {
			map.put(obj, 1);
		}
		for (Object obj: minList) {
			Integer val = map.get(obj);
			if (val != null) {
				map.put(obj, ++val);
				continue;
			}
			map.put(obj, 1);
		}
		for (Map.Entry<Object, Integer> entry : map.entrySet()){
			if (entry.getValue() == 1){
				list.add(entry.getKey());
			}
		}
		return list;
	}
	
	/**
	 * 对比两个同类型的List<Object> 返回相同的List<Object>集合
	 * @param newModel 修改后的数据集合
	 * @param oldModel 原始数据集合
	 * @return List<Object> 返回与原始集合中相同的集合
	 */
	public static List<? extends Object> getIntersectionList(List<? extends Object> newModel, List<? extends Object> oldModel) {
		Map<Object, Integer> map = new HashMap<Object, Integer>(newModel.size() + oldModel.size());
		List<Object> list = new ArrayList<Object>();
		List<Object> maxList = (List<Object>) newModel;
		List<Object> minList = (List<Object>) oldModel;
		if (oldModel.size() > newModel.size()) {
			maxList = (List<Object>) oldModel;
			minList = (List<Object>) newModel;
		}
		for (Object obj : minList) {
			map.put(obj, 1);
		}
		for (Object obj: maxList) {
			Integer val = map.get(obj);
			if (val != null) {
				map.put(obj, ++val);
				continue;
			}
			map.put(obj, 1);
		}
		for (Map.Entry<Object, Integer> entry : map.entrySet()){
			if (entry.getValue() != 1){
				list.add(entry.getKey());
			}
		}
		return list;
	}
	
	/**
	 * 对比两个同类型的List<Object> 返回与原始集合去掉重复后的集合
	 * @param newModel 修改后的数据集合
	 * @param oldModel 原始数据集合
	 * @return List<Object> 返回与原始集合去掉重复后的集合
	 */
	public static List<? extends Object> getUnionList(List<? extends Object> newModel, List<? extends Object> oldModel) {
		List<Object> maxList = (List<Object>) newModel;
		List<Object> minList = (List<Object>) oldModel;
		Set<Object> set = new HashSet<Object>();
		set.addAll(minList);
		set.addAll(maxList);
		Object[] objs = set.toArray();
		List<Object> list = Arrays.asList(objs);
		CollectionUtils.union(maxList, minList);
		return list;
	}
	/**
	 * 根据属性名获取属性值  
	 * @param fieldName
	 * @param o
	 * @return
	 */
	public static Object getFieldValueByName(Object bean ,String fieldName) {  
		try {    
           String firstLetter = fieldName.substring(0, 1).toUpperCase();    
           String getter = "get" + firstLetter + fieldName.substring(1);    
           Method method = bean.getClass().getMethod(getter, new Class[] {});    
           Object value = method.invoke(bean, new Object[] {});    
           return value;    
		} catch (Exception e) {    
			LOGGER.error(e.getMessage(),e);    
			return null;    
		}    
	}
}